home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / nn.zip / DECODE.C < prev    next >
C/C++ Source or Header  |  1989-12-31  |  7KB  |  368 lines

  1. /*
  2.  * Decode one or more uuencoded article back to binary form.
  3.  *
  4.  * UNIX/NN VERSION 
  5.  *    This version cannot be used as a stand-alone uud!
  6.  *     This version is made: 16 June 1989.
  7.  *
  8.  * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
  9.  */
  10.  
  11. #include "config.h"
  12.  
  13. export char *decode_header_file = "Decode.Headers";
  14.  
  15. #define MAXCHAR 256
  16. #define LINELEN 256
  17. #define NORMLEN 60    /* allows for 80 encoded chars per line */
  18.  
  19. #define SEQMAX 'z'
  20. #define SEQMIN 'a'
  21.  
  22. static char seqc;
  23. static int first, secnd, check, numl;
  24.  
  25. static FILE *out;
  26. static char *target;
  27. static char blank;
  28. static int chtbl[MAXCHAR], cdlen[NORMLEN + 3];
  29. static char ofname[FILENAME];
  30. static int state;
  31.  
  32. #define    NO_ADVANCE        0x10
  33.  
  34. #define    FIND_BEGIN        0x01
  35. #define    FIND_BEGIN_AFTER_ERROR    0x02
  36. #define    DECODE_TEXT        0x03
  37. #define    SKIP_TRAILING           (0x04 | NO_ADVANCE)
  38. #define    SKIP_LEADING        0x05
  39. #define    FOUND_END           (0x06 | NO_ADVANCE)
  40. #define DECODE_ERROR           (0x07 | NO_ADVANCE)
  41. #define OTHER_ERROR           (0x08 | NO_ADVANCE)
  42. #define NEW_BEGIN           (0x09 | NO_ADVANCE)
  43.  
  44. uud_start(dir)
  45. char *dir;
  46. {
  47.     target = dir;
  48.     out = NULL;
  49.     seqc = SEQMAX;
  50.     check = 1;
  51.     first = 1;
  52.     secnd = 0;
  53.     state = FIND_BEGIN;
  54. }
  55.  
  56. uud_end()
  57. {
  58.     if (out != NULL) {
  59.     fclose(out);
  60.     msg("%s INCOMPLETE -- removed", ofname);
  61.     unlink(ofname);
  62.     }
  63. }
  64.  
  65.  
  66. uudecode(ah, in)
  67. register article_header *ah;
  68. FILE *in;
  69. {
  70.     int mode, onedone, lens;
  71.     char dest[FILENAME], buf[LINELEN];
  72.  
  73.     numl = onedone = 0;
  74.  
  75.     if (state == FIND_BEGIN)
  76.     inittbls();
  77.     
  78.     /*
  79.      * search for header or translation table line.
  80.      */
  81.  
  82.     while ((state & NO_ADVANCE) || 
  83.        (ftell(in) < ah->lpos && fgets(buf, sizeof buf, in) != NULL)) {
  84.     numl++;
  85.  
  86.     switch (state) {
  87.  
  88.      case NEW_BEGIN:
  89.         if (out != NULL) {
  90.         msg("INCOMPLETE FILE: %s -- removed", ofname);
  91.         user_delay(5);
  92.         fclose(out);
  93.         out = NULL;
  94.         unlink(ofname);
  95.         }
  96.         /* fall thru */
  97.  
  98.      case FIND_BEGIN:
  99.      case FIND_BEGIN_AFTER_ERROR:
  100.         if (strncmp(buf, "table", 5) == 0) {
  101.         gettable(in);
  102.         continue;
  103.         }
  104.  
  105.         if (strncmp(buf, "begin", 5) == 0) {
  106.         lens = strlen(buf);
  107.         buf[--lens] = '\0';
  108.  
  109.         if(sscanf(buf,"begin%o%s", &mode, dest) != 2)
  110.             continue;
  111.         
  112.         if (target != NULL)
  113.             sprintf(ofname, "%s%s", target, dest);
  114.         else
  115.             strcpy(ofname, dest);
  116.             
  117.         if ((out = open_file(ofname, OPEN_CREATE)) == NULL) {
  118.             msg("Cannot create file: %s\n", ofname);
  119.             goto err;
  120.         }
  121.         chmod(ofname, mode);
  122.  
  123.         if (decode_header_file)
  124.             store_header(ah, in, target, decode_header_file);
  125.  
  126.         msg("Decoding: %s", ofname);
  127.         state = DECODE_TEXT;
  128.         }
  129.         continue;
  130.     
  131.      case SKIP_LEADING:
  132.         state = decode_line(buf);
  133.         continue;
  134.  
  135.      case DECODE_TEXT:
  136.         state = decode_line(buf);
  137.         onedone = 1;
  138.         continue;
  139.  
  140.      case FOUND_END:
  141.         fclose(out);
  142.         out = NULL;
  143.         state = FIND_BEGIN;
  144.         continue;
  145.         
  146.      case SKIP_TRAILING:
  147.         state = SKIP_LEADING;
  148.         return 0;
  149.  
  150.      case DECODE_ERROR:
  151.         state = SKIP_TRAILING;
  152.         continue;
  153.         
  154.      case OTHER_ERROR:
  155.         fclose(out);
  156.         out = NULL;
  157.         state = FIND_BEGIN_AFTER_ERROR;
  158.         goto err;
  159.     }
  160.     }
  161.     
  162.     if (onedone) {
  163.     if (state == DECODE_TEXT) state = SKIP_LEADING;
  164.     return 0;
  165.     }
  166.     
  167.     if (state == FIND_BEGIN_AFTER_ERROR) return -1;
  168.     msg("No 'begin' line");
  169.     
  170.  err:
  171.     user_delay(2);
  172.     return -1;
  173. }
  174.  
  175. /*
  176.  * decode one line, write on out file
  177.  */
  178.  
  179. static decode_line(buf)
  180. char *buf;
  181. {
  182.     char outl[LINELEN];
  183.     register char *bp, *ut;
  184.     register int *trtbl = chtbl;
  185.     register int n; 
  186.     register int blen;        /* binary length (from decoded file) */
  187.     register int rlen;        /* calculated input line length */
  188.     register int len;        /* actual input line length */
  189.     
  190.     len = strlen(buf);
  191.     if (--len < 0) return state;
  192.  
  193.     buf[len] = '\0';
  194.  
  195.     /*
  196.      * Get the binary line length.
  197.      */
  198.     if ((blen = trtbl[buf[0]]) < 0) {
  199.     if (state == SKIP_LEADING) {
  200.         if (strncmp(buf, "begin", 5) == 0)
  201.         return NEW_BEGIN;
  202.     
  203.         return SKIP_LEADING;
  204.     }    
  205.     /*
  206.      * end of uuencoded file ?
  207.      */
  208.     if (strncmp(buf, "end", 3) == 0) 
  209.         return FOUND_END;
  210.     
  211.     /*
  212.      * end of current file ? : get next one.
  213.      */
  214.     if (strncmp(buf, "include", 7) == 0) {
  215.         msg("Cannot handle 'include' lines -- unpack with uud");
  216.         return OTHER_ERROR;
  217.     }
  218.  
  219.     /*
  220.      * trailing garbage
  221.      */
  222.     return SKIP_TRAILING;
  223.     }
  224.     
  225.     rlen = cdlen[blen];
  226.     if (len != rlen && state == SKIP_LEADING)
  227.     return SKIP_LEADING;
  228.     
  229.     /*
  230.      * Is it the empty line before the end line ?
  231.      */
  232.     if (blen == 0) return state;
  233.     
  234.     /*
  235.      * Pad with blanks.
  236.      */
  237.     for (bp = buf + len, n = rlen - len; --n >= 0; ) *bp++ = blank;
  238.     
  239.     /*
  240.      * Verify
  241.      */
  242.     for (n = rlen, bp = buf; --n >= 0; bp++) 
  243.     if (trtbl[*bp] < 0) {
  244.         if (state == SKIP_LEADING) return SKIP_LEADING;
  245.         return DECODE_ERROR;
  246.     }
  247.     
  248.     /*
  249.      * Check for uuencodes that append a 'z' to each line....
  250.      */
  251.     if (check)
  252.     if (secnd) {
  253.         secnd = 0;
  254.         if (buf[rlen] == SEQMAX) check = 0;
  255.     } else if (first) {
  256.         first = 0;
  257.         secnd = 1;
  258.         if (buf[rlen] != SEQMAX) check = 0;
  259.     }
  260.     
  261.     /*
  262.      * There we check.
  263.      */
  264.     if (check) {
  265.     if (buf[rlen] != seqc) {
  266.         if (state == SKIP_LEADING) return SKIP_LEADING;
  267.         return DECODE_ERROR;
  268.     }
  269.     
  270.     if (--seqc < SEQMIN) seqc = SEQMAX;
  271.     }
  272.     
  273.     /*
  274.      * output a group of 3 bytes (4 input characters).
  275.      * the input chars are pointed to by p, they are to
  276.      * be output to file f. blen is used to tell us not to
  277.      * output all of them at the end of the file.
  278.      */
  279.     ut = outl;
  280.     n = blen;
  281.     bp = &buf[1];
  282.     while (--n >= 0) {
  283.     *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
  284.     if (n > 0) {
  285.         *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2);
  286.         n--;
  287.     }
  288.     if (n > 0) {
  289.         *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
  290.         n--;
  291.     }
  292.     bp += 4;
  293.     }
  294.     if (fwrite(outl, 1, blen, out) <= 0) {
  295.     msg("Error on writing decoded file");
  296.     return OTHER_ERROR;
  297.     }
  298.  
  299.     return DECODE_TEXT;
  300. }
  301.  
  302.  
  303.  
  304. /*
  305.  * Install the table in memory for later use.
  306.  */
  307. static inittbls()
  308. {
  309.     register int i, j;
  310.     
  311.     /*
  312.      * Set up the default translation table.
  313.      */
  314.     for (i = 0; i < ' '; i++) chtbl[i] = -1;
  315.     for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j;
  316.     for (i = ' ' + 64; i < MAXCHAR; i++) chtbl[i] = -1;
  317.     chtbl['`'] = chtbl[' '];    /* common mutation */
  318.     chtbl['~'] = chtbl['^'];    /* an other common mutation */
  319.     blank = ' ';
  320.     /*
  321.      * set up the line length table, to avoid computing lotsa * and / ...
  322.      */
  323.     cdlen[0] = 1;
  324.     for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
  325.     cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
  326. }
  327.  
  328. static gettable(in)
  329. FILE *in;
  330. {
  331.     char buf[LINELEN];
  332.     register int c, n = 0;
  333.     register char *cpt;
  334.     
  335.     for (c = 0; c <= MAXCHAR; c++) chtbl[c] = -1;
  336.     
  337.     for (;;) {
  338.     
  339.     if (fgets(buf, sizeof buf, in) == NULL) {
  340.         msg("EOF while in translation table.\n");
  341.         return -1;
  342.     }
  343.     numl++;
  344.     if (strncmp(buf, "begin", 5) == 0) {
  345.         msg("Incomplete translation table.\n");
  346.         return -1;
  347.     }
  348.     cpt = buf + strlen(buf) - 1;
  349.     *cpt = ' ';
  350.     while (*(cpt) == ' ') {
  351.         *cpt = 0;
  352.         cpt--;
  353.     }
  354.     cpt = buf;
  355.     while (c = *cpt) {
  356.         if (chtbl[c] != -1) {
  357.         msg("Duplicate char in translation table.\n");
  358.         return -1;
  359.         }
  360.         if (n == 0) blank = c;
  361.         chtbl[c] = n++;
  362.         if (n >= 64) return 0;
  363.         cpt++;
  364.     }
  365.     }
  366. }
  367.  
  368.